package nl.windgazer.arachne.mixins;

import java.util.Locale;
import java.util.Map;
import java.util.PropertyResourceBundle;

import nl.windgazer.arachne.services.ArachneModule;
import nl.windgazer.arachne.services.ArachnePrivileges;
import nl.windgazer.arachne.services.messages.InterceptedMessageVO;
import nl.windgazer.arachne.services.messages.MessageInterceptEventListener;
import nl.windgazer.arachne.util.ArachneSymbolConstants;

import org.apache.log4j.Logger;
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.Link;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.annotations.SetupRender;
import org.apache.tapestry5.internal.util.LocaleUtils;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.Environment;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.apache.tapestry5.services.messages.ComponentMessagesSource;

/**
 * This Mixin provides a MessageInterceptEventListener on the environment in order to intercept
 * any calls to the messages properties. Subsequently a javascript object is initialized in order
 * to alter the intercepted messages.
 * 
 * A T5 Module must decorate / override the necessary services in order for this to work.
 * @author mreuring
 * @see ArachneModule#decorateComponentMessagesSource(ComponentMessagesSource original)
 *
 */
@Import( stylesheet={"MessagesInterceptorTranslator.css"} )
public class MessagesInterceptorTranslator {

	private static final Logger logger = Logger.getLogger(MessagesInterceptorTranslator.class);

	public static final String SAVE_MESSAGE_EVENT = "saveMessage";

	/**
	 * Not to happy about this, but for now I'll have to live with it, I don't yet know how to do this 'better'
	 */
    private static final String PARAM_NAME_KEY = "t:messagekey";
    private static final String PARAM_NAME_LOCALE = "t:locale";
    private static final String PARAM_NAME_MSG = "t:messagevalue";

	//Injects and Persists

    @Inject
    private ArachnePrivileges _ap;

    @Inject
    private Environment _environment;

    @Inject
    private Request _request;

    @Inject
    private Messages _messages;

    @Inject
    private ComponentResources _cr;

	@Inject
	private JavaScriptSupport _jss;

    @Inject
    @Path("../mixins/livepipe.js")
    private Asset _livepipe;

    @Inject
    @Path("../mixins/hotkey.js")
    private Asset _hotkey;

    @Inject
    @Path("../mixins/MessagesInterceptorTranslator.js")
    private Asset _mit;

	@Inject
	private Locale _locale;

	@Inject
	private MessageInterceptEventListener _miel;

	@Inject
	@Symbol(SymbolConstants.APPLICATION_CATALOG)
	private String appCatalog;

	@Inject
	@Symbol(ArachneSymbolConstants.TRANSLATOR_ROLE)
	private String role;

	@Inject
	@Symbol(ArachneSymbolConstants.TRANSLATION_ENABLED)
	private boolean translate;

	//Properties and Parameters
	//Components
	//Events

	@SetupRender
	public void setupMessagesInterception(MarkupWriter writer) {
		//Do stuff just before the page starts rendering here...
		if (translate) {
			if (_ap.hasRole(role)) {
				_miel.setMarkupWriter(writer);
				_environment.push(MessageInterceptEventListener.class, _miel);
			}
		} else {
			logger.debug("Refraining from adding a MessageInterceptor to the Environment, translation is set to be disabled.");
		}
 	}

    @AfterRender
    public void addMessagesTranslatorInit() {
		//Clean up and add required assets if translations are enabled
		if (translate) {
			try  {
				if (_ap.hasRole(role)) {
			        _environment.pop(MessageInterceptEventListener.class);
			        String bundle = appCatalog;
			        bundle = bundle.substring(0, bundle.length() - 11); //cut of .properties
			        bundle = bundle.replaceAll("/", "."); //Slashes back to dots
			        MessagesImpl i8n = new MessagesImpl(Locale.getDefault(), PropertyResourceBundle.getBundle(bundle));
			        final Map<String, InterceptedMessageVO> intercepted = _miel.getIntercepted();
			        final JSONObject messagesJS = new JSONObject();
			        
			        for (Map.Entry<String, InterceptedMessageVO> e:intercepted.entrySet()) {
			        	JSONObject im = e.getValue().toJSON();
			        	im.put("i8n", i8n.get(e.getKey()));
			        	messagesJS.put(e.getKey(), im);
			        }
			        
			        Link save = _cr.createEventLink(SAVE_MESSAGE_EVENT);
			
					JSONObject config = new JSONObject();
					JSONObject params = new JSONObject();
					params.put("key", PARAM_NAME_KEY);
					params.put("locale", PARAM_NAME_LOCALE);
					params.put("message", PARAM_NAME_MSG);
					config.put("params", params);
					config.put("locale", _locale.toString());
					config.put("saveURI", save.  toAbsoluteURI());
					config.put("confirmMessage", _messages.get("messagestranslator.confirm"));
					config.put("authMessage", _messages.get("messagestranslator.authenticationFailed"));
					config.put("commMessage", _messages.get("messagestranslator.communicationFailed"));
					config.put("timeOut", 10);
					config.put("messages", messagesJS);
			
					_jss.importJavaScriptLibrary(_livepipe);
					_jss.importJavaScriptLibrary(_hotkey);
					_jss.importJavaScriptLibrary(_mit);
					_jss.addInitializerCall("createNewMessagesInterceptorTranslator", config);
				}
			} catch (Exception e) {
				logger.error("Exception occured while attempting to initialise the translation tools!");
				logger.error(e);
			}
		}
    }

	public JSONObject onSaveMessage() {
		final String key = _request.getParameter(PARAM_NAME_KEY);
		final Locale locale = LocaleUtils.toLocale(_request.getParameter(PARAM_NAME_LOCALE));

		final String msg = _request.getParameter(PARAM_NAME_MSG);
		_miel.addMsg(key, msg, _cr.getPageName(), locale);
		InterceptedMessageVO imVO = new InterceptedMessageVO(key, msg, msg, null); //This class doesn't (yet) know the 'live' value or the international one...
		return imVO.toJSON();
	}

	//Other (check for business-logic, it should not remain here)

}
